package soko.sokoban;

/**
 * Class Tile represents a walkable tile on a screen.
 */
public class Tile {

	/**
	 * The x-coordinate of this Tile.
	 */
	private int x;
	
	/**
	 * The y-coordinate of this Tile.
	 */
	private int y;
	
	/**
	 * The position of this Tile. The most upper-left tile has position zero.
	 */
	private int position;
	
	/**
	 * The Representation of this Tile.
	 */
	private Representation representation;
	
	/**
	 * The Tile directly above this Tile. Null if there is no such Tile.
	 */
	private Tile upTile;
	
	/**
	 * The Tile directly below this Tile. Null if there is no such Tile.
	 */
	private Tile downTile;
	
	/**
	 * The Tile directly left of this Tile. Null if there is no such Tile.
	 */
	private Tile leftTile;
	
	/**
	 * The Tile directly right of this Tile. Null if there is no such Tile.
	 */
	private Tile rightTile;

	/**
	 * Constructs a new Tile.
	 * @param representation the Representation of this Tile.
	 * @param x the x-coordinate of this Tile.
	 * @param y the y-coordinate of this Tile.
	 * @param position the position of this Tile.
	 */
	public Tile(Representation representation, int x, int y, int position) {
		this.representation = representation;
		this.x = x;
		this.y = y;
		this.position = position;
	}

	/**
	 * Gets the Representation of this Tile.
	 * @return the Representation.
	 */
	public Representation getRepresentation() {
		return representation;
	}

	/**
	 * Returns whether this Tile is a block or a block on a goal.
	 * @return whether this Tile is a block or a block on a goal.
	 */
	public boolean isBlock() {
		return representation == Representation.BLOCK || representation == Representation.BLOCK_ON_GOAL;
	}

	/**
	 * Returns whether this Tile is a man or a man on a goal.
	 * @return whether this Tile is a man or a man on a goal.
	 */
	public boolean isMan() {
		return representation == Representation.MAN || representation == Representation.MAN_ON_GOAL;
	}

	/**
	 * Returns whether this Tile is a goal or a man on a goal or a block on a goal.
	 * @return whether this Tile is a goal or a man on a goal or a block on a goal.
	 */
	public boolean isGoal() {
		return representation == Representation.GOAL || representation == Representation.BLOCK_ON_GOAL
				|| representation == Representation.MAN_ON_GOAL;
	}

	/**
	 * Returns the x-coordinate of this Tile.
	 * 
	 * @return the x-coordinate of this Tile.
	 */
	public int getX() {
		return x;
	}

	/**
	 * Returns the y-coordinate of this Tile.
	 * 
	 * @return the y-coordinate of this Tile.
	 */
	public int getY() {
		return y;
	}

	/**
	 * A String representation of this Tile.
	 * @return the String representation of this Tile.
	 */
	@Override
	public String toString() {
		return representation + "_" + x + "_" + y + "_" + position;
	}

	/**
	 * Gets the position of this Tile.
	 * 
	 * @return the position of this Tile.
	 */
	public int getPosition() {
		return position;
	}

	/**
	 * Sets the Tile directly above this Tile. Can be null if there is no such Tile.
	 * @param upTile the Tile.
	 */
	public void setUpTile(Tile upTile) {
		this.upTile = upTile;
	}

	/**
	 * Sets the Tile directly below this Tile. Can be null if there is no such Tile.
	 * @param downTile the Tile.
	 */
	public void setDownTile(Tile downTile) {
		this.downTile = downTile;
	}

	/**
	 * Sets the Tile directly left to this Tile. Can be null if there is no such Tile.
	 * @param leftTile the Tile.
	 */
	public void setLeftTile(Tile leftTile) {
		this.leftTile = leftTile;
	}

	/**
	 * Sets the Tile directly right to this Tile. Can be null if there is no such Tile.
	 * @param rightTile the Tile.
	 */
	public void setRightTile(Tile rightTile) {
		this.rightTile = rightTile;
	}

	/**
	 * Get the Tile directly in to a particular Direction.
	 * @param direction the Direction
	 * @return The Tile directly in a particular Direction.
	 */
	public Tile getTile(Direction direction) {

		if (direction == Direction.DOWN) {
			return getDownTile();
		} else if (direction == Direction.UP) {
			return getUpTile();
		} else if (direction == Direction.LEFT) {
			return getLeftTile();
		} else if (direction == Direction.RIGHT) {
			return getRightTile();
		} else {
			throw new RuntimeException();
		}

	}

	/**
	 * Gets the Tile directly below this Tile. Can be null if there is no such Tile.
	 * @return the Tile.
	 */
	public Tile getDownTile() {
		return downTile;
	}

	/**
	 * Gets the Tile directly above this Tile. Can be null if there is no such Tile.
	 * @return the Tile.
	 */
	public Tile getUpTile() {
		return upTile;
	}

	/**
	 * Gets the Tile directly left to this Tile. Can be null if there is no such Tile.
	 * @return the Tile.
	 */
	public Tile getLeftTile() {
		return leftTile;
	}

	/**
	 * Gets the Tile directly right to this Tile. Can be null if there is no such Tile.
	 * @return the Tile.
	 */
	public Tile getRightTile() {
		return rightTile;
	}
}